package gui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

import simulation.Util;
import simulation.initiatives.AbstractEngine;

import common.Constants;
import common.IGrid;

public class EarthGrid extends JPanel implements Runnable, MouseMotionListener {
  private static final long serialVersionUID = -1108120968981962997L;
  
  private BufferedImage imgTransparent;
  private BufferedImage imgStatic;
  private float[] scales = { 1f, 1f, 1f, Constants.OPACITY }; //last index controls the transparency
  float[] offsets = new float[4];
  private int degreeSeparation;
  private int pixelsPerCellX; //number of pixels per latitudal division
  private int pixelsPerCellY; //number of pixels per longitudal division
  private int imgWidth; // in pixels
  private int imgHeight; // in pixels
  private int numCellsX;
  private int numCellsY;
  private int radius;
  private boolean paintInitialColors = true;
  private IGrid grid;
  
  public EarthGrid() {
    try {
      URL imgURL = getClass().getResource("earth-white.jpg");
      imgStatic = ImageIO.read(imgURL);
    }
    catch (IOException e) {
      e.printStackTrace();
    }
//    enableTooltips();
//    ToolTipManager.sharedInstance().setInitialDelay(2);
    setGridSize(Constants.DEFAULT_GRID_SPACING);
    setIgnoreRepaint(true);
  }
  
  public void setGridSize(int degreeSeparation) {
    this.degreeSeparation = degreeSeparation;
    
    numCellsX = 360 / degreeSeparation;      
    pixelsPerCellX = imgStatic.getWidth() / numCellsX;
    imgWidth = numCellsX * pixelsPerCellX;

    numCellsY = 180 / degreeSeparation;
    pixelsPerCellY = imgStatic.getHeight() / numCellsY;
    imgHeight = numCellsY * pixelsPerCellY;
    radius = imgHeight/2;
    
    //create an image capable of transparency; then draw our image into it
    imgTransparent = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_ARGB);
    Graphics g = imgTransparent.getGraphics();
    g.drawImage(imgStatic, 0, 0, imgWidth, imgHeight, null);  
  }
  
  public void paint(Graphics g) {
    //the order in which these are called does matter
    if(paintInitialColors)
      initCellColors(g);
    else 
      fillCellColors(g);
    drawTransparentImage(g);
    drawGrid(g);
  }
  
  private void initCellColors(Graphics g) {
    g.setColor(colorPicker((int)Constants.DEFAULT_CELL_TEMP));
    g.fillRect(0, 0, imgWidth, imgHeight);
  }
  
  public void updateGrid(AbstractEngine engine) {
    engine.step();
    updateGrid(engine.getGrid());
  }
  
  public void updateGrid(IGrid grid) {
    this.grid = grid;
    paintInitialColors = false;    
    repaint();
  }
  
  public int getRadius() {
    return radius;
  }

  /**
   * This is used implicitly by swing to do it's layout job properly
   */
  public int getWidth() {
    return imgWidth;
  }
  
  private void fillCellColors(Graphics g) {
    int cellX=0, cellY=0;
    int cellWidth = pixelsPerCellX;
    
    for (int x = 0; x < numCellsX; x++) {      
      for (int y = 0; y < numCellsY; y++) {
        double newTemp = grid.getTemperature(x, y);
        int colorValue = new Double(newTemp).intValue();
        int cellHeight = grid.getCellHeight(x, y);
        
        g.setColor(colorPicker(colorValue));
        g.fillRect(cellX, cellY, cellWidth, cellHeight);
        cellY += cellHeight;
//        System.out.print("\n["+x+", "+y+"] color: " + colorValue);
      }      
      cellX += cellWidth;
      cellY = 0;
    }
  }
  
  private void drawTransparentImage(Graphics g) {    
    RescaleOp rop = new RescaleOp(scales, offsets, null);
    Graphics2D g2d = (Graphics2D)g;
    g2d.drawImage(imgTransparent, rop, 0, 0);
  }
  
  private void drawGrid(Graphics g) {
    g.setColor(Color.black);
    
    //draw longitude lines
    for(int x = 0; x <= imgWidth; x += pixelsPerCellX) {
      g.drawLine(x, 0, x, imgHeight);      
    }
    
    //draw scaled latitude lines
    for(int lat = 0; lat <= 90; lat += degreeSeparation) {
      int y = (int)Util.distToEquator(lat, radius);
      g.drawLine(0, radius-y, imgWidth, radius-y);
      g.drawLine(0, radius+y, imgWidth, radius+y);
    }
    
    g.setColor(Color.blue);
    g.drawLine(imgWidth/2, 0, imgWidth/2, imgHeight); //prime meridian
    g.drawLine(0, imgHeight/2, imgWidth, imgHeight/2); // equator
  }
  
  public void setMapOpacity(float value) {
    scales[3] = value;
  }

  public void reset() {
    paintInitialColors = true;
    enableTooltips();
  }
  
  private Color colorPicker(int v) {
    int b = 0;
    int g = 0;
    int r = 0;

    if(v <= -100)
    {
      b = 170;
        g = 100;
        r = 170;
    }
    else if (v <= -46)
    {
      v = -1 * v;
        b = 255;
        g = 145 - (v * 10) % 115;
        r = 255;
    }
    else if(v <= -23 && v > -46)
    {
      v = -1 * v;
      b = 255;
        g = 145;
        r = 145 + (v * 5) % 115;
    }
    else if(v < 0 && v > -23)
    {
      v = -1 * v;
      b = 255;
        g = 145;
        r = 145 - (v * 5);
    }
    else if (v == 0) {
      b = 225;
      g = 145;
      r = 145;
    }
    else if (v > 0 && v < 23) {
      b = 255;
      g = 145 + (v * 5);
      r = 145;
    }
    else if (v >= 23 && v < 46) {

      b = 255 - (v * 5) % 115;
      g = 255;
      r = 145;
    }
    else if (v >= 46 && v < 69) {
      b = 145;
      g = 255;
      r = 145 + (v * 5) % 115;
    }
    else if (v >= 69 && v < 92) {
      b = 145;
      g = 255 - (v * 5) % 115;
      r = 255;
    }
    else {
      b = 145 - (v * 10) % 115;
      g = 145 - (v * 10) % 115;
      r = 255;
    }
    return new Color(r, g, b);
  }
  
  public void run() {}
  public void mouseDragged(MouseEvent arg0) {}
  public void mouseMoved(MouseEvent evt) {
    if(grid != null) {
//      Point pt = evt.getPoint();
//      int x = (pt.x)/(pixelsPerCellX);
//      
//      double distToEquator = Math.abs(pt.y - radius);
//      
//      //another equation is distToEquator = radius * sin(latitude) - so we'll solve for latitude
//      double latitude = Math.asin(Math.toRadians(distToEquator/(double)radius));
//      double deg = Math.toDegrees(latitude);
//      //get the y coordinate of the cell relative to the equator
//      int y = (int)(Math.toDegrees(latitude) / degreeSeparation);
//            
//      String temp = String.valueOf(grid.getTemperature(x, y));
//      this.setToolTipText(temp);
    }
    else
      this.setToolTipText(String.valueOf(Constants.DEFAULT_CELL_TEMP));
  }
  
  public void enableTooltips() {
    this.addMouseMotionListener(this);
  }
  
  public void disableTooltips() {
    this.removeMouseMotionListener(this);
    this.setToolTipText(null);
  }
  
}
